# coding:utf-8
from dataclasses import dataclass
from queue import Queue
from time import sleep
from typing import Callable, Any
import traceback

from PyQt6.QtCore import QThread, pyqtSignal, QThreadPool
from loguru import logger


@dataclass
class FuncSignalData:
    success: bool = True
    message: str = '函数运行成功'
    result: Any = None


class FuncThread(QThread):
    funcSignal = pyqtSignal(FuncSignalData)
    logSignal = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.func = None
        self.args = None
        self.kwargs = None
        self.isShowLog = False

    def run(self):
        try:
            if self.isShowLog:
                result = self.func(*self.args, **self.kwargs, log_func=self.logSignal.emit)
            else:
                result = self.func(*self.args, **self.kwargs)
            self.funcSignal.emit(FuncSignalData(result=result))
        except Exception as e:
            exc = traceback.format_exc()
            logger.error(exc)
            self.funcSignal.emit(FuncSignalData(success=False, message=str(exc)))

    def setFunc(self, func: Callable, *args, **kwargs):
        self.func = func
        self.args = args
        self.kwargs = kwargs
        self.isShowLog = kwargs.pop('isShowLog', False)
        self.start()


class FuncThreadPool(QThread):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.queue = Queue()
        self.pool = QThreadPool.globalInstance()

    def run(self):
        while not self.queue.empty():
            func, args, kwargs = self.queue.get()
            try:
                self.pool.start(lambda: func(*args, **kwargs))
            except Exception as e:
                logger.exception(e)

    def addTask(self, func: Callable, *args, **kwargs):
        self.queue.put((func, args, kwargs))


if __name__ == '__main__':
    from PyQt6.QtCore import QCoreApplication

    app = QCoreApplication([])
    funcThread = FuncThreadPool()


    def testFunc(a, b, log_func=None):
        if log_func:
            log_func('开始运行函数')
        sleep(1)
        print(a, b)
        print(a + b,'\n')


    for i in range(10):
        print(i)
        funcThread.addTask(testFunc, i, i)
    funcThread.start()
    app.exec()
